package HLLib.game;

import HLCode.HLClass;
import HLCode.HLClassManager;
import HLCode.HLClassManager_H;
import HLCode.HLObject;
import HLLib.base.HLGraphics_H;
import HLLib.base.HLList;
import HLLib.base.HLMath;
import HLLib.base.HLPoint;
import HLLib.base.HLRectangle;
import HLLib.io.HLFile;

public class HLCDGroupAllTrans extends HLList implements HLGraphics_H {
    public HLClass GetClass(HLClassManager classManager) {
        return classManager.GetLibClass(HLClassManager_H.CLASS_GROUP_TYPE_LIB_GAME, HLClassManager_H.LIB_CLASS_GAME_CDGroupAllTrans);
    }

    public int GetInt(int index) {
        return super.GetInt(index);
    }

    public void SetInt(int index, int value) {
        super.SetInt(index, value);
    }

    public boolean GetBoolean(int index) {
        return super.GetBoolean(index);
    }

    public void SetBoolean(int index, boolean value) {
        super.SetBoolean(index, value);
    }

    public HLObject GetObject(int index) {
        return super.GetObject(index);
    }

    public void SetObject(int index, HLObject value) {
        super.SetObject(index, value);
    }

    public HLCDGroupAllTrans() {
        super(TRANS_COUNT);
        for (int i = 0; i < TRANS_COUNT; i++) {
            items[i] = new HLList();
        }
    }

    static public HLList GetTransCDGroup(HLList cdGroup, int trans, int transX, int transY, boolean symmetryByPixel) {
        HLList newCDGroup = new HLList(cdGroup.items.length);

        for (int i = 0; i < cdGroup.items.length; i++) {
            HLCD cd = (HLCD) cdGroup.items[i];
            newCDGroup.items[i] = cd;
            HLRectangle rect = HLMath.GetTransRect(//
                    cd.x,//
                    cd.y,//
                    cd.width,//
                    cd.height,//
                    transX, transY,//
                    trans,//
                    symmetryByPixel);

            HLCD newCD = new HLCD();

            newCD.mask = cd.mask;

            newCD.x = (short) rect.x;
            newCD.y = (short) rect.y;
            newCD.width = (short) rect.width;
            newCD.height = (short) rect.height;
            newCD.z = cd.z;
            newCD.length = cd.length;
            newCDGroup.items[i] = newCD;
        }

        return newCDGroup;
    }

    public static boolean CDTouchRect(HLCD cd0, int x0, int y0, HLCD cd1, int x1, int y1, boolean processStatus) {
        return (!processStatus || (cd0.mask & cd1.mask) != 0) && CDTouchRect1(cd0, x0, y0, cd1, x1, y1);
    }

    public static boolean CDTouchRect1(HLCD cd0, int x0, int y0, HLCD cd1, int x1, int y1) {
        return RectTouchRect(//
                cd0.x + x0,//
                cd0.y + y0,//
                cd0.width,//
                cd0.height,//
                cd1.x + x1,//
                cd1.y + y1,//
                cd1.width,//
                cd1.height);
    }

    public static boolean CDTouchCuboid(HLCD cd0, int x0, int y0, int z0, HLCD cd1, int x1, int y1, int z1, boolean processStatus) {
        return (!processStatus || (cd0.mask & cd1.mask) != 0) && CDTouchCuboid1(cd0, x0, y0, z0, cd1, x1, y1, z1);
    }

    public static boolean CDTouchCuboid1(HLCD cd0, int x0, int y0, int z0, HLCD cd1, int x1, int y1, int z1) {
        return CuboidTouchCuboid(//
                cd0.x + x0,//
                cd0.y + y0,//
                cd0.z + z0,//
                cd0.width,//
                cd0.height,//
                cd0.length,//
                cd1.x + x1,//
                cd1.y + y1,//
                cd1.z + z1,//
                cd1.width,//
                cd1.height,//
                cd1.length);
    }

    public static boolean PolygonTouchPoint(HLList pointList, int pointX, int pointY) {
        int i, j;
        int y;
        int miny, maxy;
        int x1, y1;
        int x2, y2;
        int ind1, ind2;
        int ints;
        int[] polyInts;
        int nPoints = pointList.Count();
        if (nPoints < 3) {
            return false;
        }
        polyInts = new int[nPoints];
        miny = ((HLPoint) pointList.items[0]).y;
        maxy = miny;
        for (i = 1; i < nPoints; i++) {
            if (((HLPoint) pointList.items[i]).y < miny) {
                miny = ((HLPoint) pointList.items[i]).y;
            } else if (((HLPoint) pointList.items[i]).y > maxy) {
                maxy = ((HLPoint) pointList.items[i]).y;
            }
        }
        for (y = miny; y <= maxy; y++) {
            ints = 0;
            for (i = 0; i < nPoints; i++) {
                if (i == 0) {
                    ind1 = nPoints - 1;
                    ind2 = 0;
                } else {
                    ind1 = i - 1;
                    ind2 = i;
                }
                y1 = ((HLPoint) pointList.items[ind1]).y;
                y2 = ((HLPoint) pointList.items[ind2]).y;
                if (y1 < y2) {
                    x1 = ((HLPoint) pointList.items[ind1]).x;
                    x2 = ((HLPoint) pointList.items[ind2]).x;
                } else if (y1 > y2) {
                    y2 = ((HLPoint) pointList.items[ind1]).y;
                    y1 = ((HLPoint) pointList.items[ind2]).y;
                    x2 = ((HLPoint) pointList.items[ind1]).x;
                    x1 = ((HLPoint) pointList.items[ind2]).x;
                } else {
                    continue;
                }
                if ((y >= y1) && (y < y2)) {
                    polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
                } else if ((y == maxy) && (y > y1) && (y <= y2)) {
                    polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
                }
            }
            for (i = nPoints; --i >= 0;) {
                for (j = 0; j < i; j++) {
                    if (polyInts[j] > polyInts[j + 1]) {
                        int T = polyInts[j];
                        polyInts[j] = polyInts[j + 1];
                        polyInts[j + 1] = T;
                    }
                }
            }
            for (i = 0; i < ints; i += 2) {
                if (pointY == y) {
                    if (pointX >= polyInts[i] && pointX <= polyInts[i + 1]) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    // ????????????
    public static boolean RectTouchRect(int x0, int y0, int width0, int height0, int x1, int y1, int width1, int height1) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RectTouchRect.Ccode
        return width0 > 0 && height0 > 0 && width1 > 0 && height1 > 0 && x0 < x1 + width1 && x1 < x0 + width0 && y0 < y1 + height1 && y1 < y0 + height0;
        // moduleEndOfHLLib\HLCDGroupAllTrans.RectTouchRect.Ccode
    }

    // ????????????
    public static boolean CuboidTouchCuboid(int x0, int y0, int z0, int width0, int height0, int lenth0, int x1, int y1, int z1, int width1, int height1, int lenth1) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.CuboidTouchCuboid.Ccode
        return lenth0 > 0 && lenth1 > 0 && z0 < z1 + lenth1 && z1 < z0 + lenth0 && RectTouchRect(x0, y0, width0, height0, x1, y1, width1, height1);
        // moduleEndOfHLLib\HLCDGroupAllTrans.CuboidTouchCuboid.Ccode
    }

    // ????????????
    public static boolean RectTouchLine(int rectX, int rectY, int rectWidth, int rectHeight, int lineX0, int lineY0, int lineX1, int lineY1) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RectTouchLine.Ccode
        return RectTouchRect(rectX, rectY, rectWidth, rectHeight, lineX0 <= lineX1 ? lineX0 : lineX1, lineY0 <= lineY1 ? lineY0 : lineY1, Math.abs(lineX0 - lineX1) + 1, Math.abs(lineY0 - lineY1) + 1) && (RectTouchPoint(rectX, rectY, rectWidth, rectHeight, lineX0, lineY0) || RectTouchPoint(rectX, rectY, rectWidth, rectHeight, lineX1, lineY1) || LineTouchLine(rectX, rectY, rectX + rectWidth - 1, rectY, lineX0, lineY0, lineX1, lineY1)// TOP
                || LineTouchLine(rectX, rectY, rectX, rectY + rectHeight - 1, lineX0, lineY0, lineX1, lineY1)// LEFT
                || LineTouchLine(rectX + rectWidth - 1, rectY, rectX + rectWidth - 1, rectY + rectHeight - 1, lineX0, lineY0, lineX1, lineY1)// RIGHT
        || LineTouchLine(rectX, rectY + rectHeight - 1, rectX + rectWidth - 1, rectY + rectHeight - 1, lineX0, lineY0, lineX1, lineY1)// BOTTOM
                );
        // moduleEndOfHLLib\HLCDGroupAllTrans.RectTouchLine.Ccode
    }

    // ????????????
    public static boolean RectTouchPoint(int rectX, int rectY, int rectWidth, int rectHeight, int x, int y) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RectTouchPoint.Ccode
        return RectTouchPoint1(rectX, rectY, rectX + rectWidth - 1, rectY + rectHeight - 1, x, y);
        // moduleEndOfHLLib\HLCDGroupAllTrans.RectTouchPoint.Ccode
    }

    // ????????????
    public static boolean RectTouchPoint1(int rectX0, int rectY0, int rectX1, int rectY1, int x, int y) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RectTouchPoint1.Ccode
        return x >= rectX0 && x <= rectX1 && y >= rectY0 && y <= rectY1;
        // moduleEndOfHLLib\HLCDGroupAllTrans.RectTouchPoint1.Ccode
    }

    static int cw_test(int ax, int ay, int bx, int by, int cx, int cy) {
        int lhs = (by - ay) * (cx - ax);
        int rhs = (cy - ay) * (bx - ax);
        if (lhs == rhs) {
            return 0;
        } else if (lhs < rhs) {
            return 1;
        } else {
            return 2;
        }
    }

    static boolean bound(int x, int a, int b) {
        return a <= x && x <= b || a >= x && x >= b;
    }

    static boolean bound_inside(int x, int y, int ax, int ay, int bx, int by) {
        return bound(x, ax, bx) && bound(y, ay, by);
    }

    public static boolean LineTouchLine(int line0X0, int line0Y0, int line0X1, int line0Y1, int line1X0, int line1Y0, int line1X1, int line1Y1) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.LineTouchLine.Ccode
        int t1 = cw_test(line0X0, line0Y0, line1X0, line1Y0, line1X1, line1Y1);
        int t2 = cw_test(line0X1, line0Y1, line1X0, line1Y0, line1X1, line1Y1);
        int t3 = cw_test(line1X0, line1Y0, line0X0, line0Y0, line0X1, line0Y1);
        int t4 = cw_test(line1X1, line1Y1, line0X0, line0Y0, line0X1, line0Y1);

        return 3 == (t1 | t2) && 3 == (t3 | t4) || //
                0 == t1 && bound_inside(line0X0, line0Y0, line1X0, line1Y0, line1X1, line1Y1) || //
                0 == t2 && bound_inside(line0X1, line0Y1, line1X0, line1Y0, line1X1, line1Y1) || //
                0 == t3 && bound_inside(line1X0, line1Y0, line0X0, line0Y0, line0X1, line0Y1) || //
                0 == t4 && bound_inside(line1X1, line1Y1, line0X0, line0Y0, line0X1, line0Y1);
        // HLPoint p1 = HLMath.vectorSub(line1X1, line1Y1, line1X0, line1Y0);
        // HLPoint p5 = HLMath.vectorSub(line0X1, line0Y1, line0X0, line0Y0);
        // return
        // HLMath.vectorMul(p1, HLMath.vectorSub(line0X0, line0Y0, line1X0,
        // line1Y0)) * HLMath.vectorMul(HLMath.vectorSub(line0X1, line0Y1,
        // line1X0, line1Y0), p1) >= 0
        // &&
        // HLMath.vectorMul(p5, HLMath.vectorSub(line1X0, line1Y0, line0X0,
        // line0Y0)) * HLMath.vectorMul(HLMath.vectorSub(line1X1, line1Y1,
        // line0X0, line0Y0), p5) >= 0;
        // moduleEndOfHLLib\HLCDGroupAllTrans.LineTouchLine.Ccode
    }

    // ???????????
    public static boolean LineTouchPoint(int lineX0, int lineY0, int lineX1, int lineY1, int x, int y) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.LineTouchPoint.Ccode
        return HLMath.vectorMul(HLMath.vectorSub(x, y, lineX0, lineY0), HLMath.vectorSub(lineX1, lineY1, lineX0, lineY0)) == 0 && Math.min(lineX0, lineX1) <= x && Math.max(lineX0, lineX1) >= x && Math.min(lineY0, lineY1) <= y && Math.max(lineY0, lineY1) >= y;
        // moduleEndOfHLLib\HLCDGroupAllTrans.LineTouchPoint.Ccode
    }

    // ???????????
    public static boolean PointTouchPoint(int x0, int y0, int x1, int y1) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.PointTouchPoint.Ccode
        return x0 == x1 && y0 == y1;
        // moduleEndOfHLLib\HLCDGroupAllTrans.PointTouchPoint.Ccode
    }

    void LoadFromFile(HLStageLoadInfo worldNeedLoader, boolean is3D) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.LoadFromFile.Ccode
        // ????????
        HLFile file = new HLFile();

        file.Load1("cd.cfg");

        if (file.data != null)// ??????
        {
            // ???cd????
            int tempCount = file.ReadUIntByByteCount(worldNeedLoader.CDTypeByteCount);

            HLList cdGroup = new HLList(tempCount);

            items[TRANS_NONE] = cdGroup;

            for (int i = 0; i < tempCount; i++) {
                HLCD cd = new HLCD();
                cdGroup.items[i] = cd;
                // mask
                cd.mask = file.ReadIntByByteCount(worldNeedLoader.CDMaskByteCount);

                // ???????
                cd.x = (short) file.ReadIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                cd.y = (short) file.ReadIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                if (is3D) {
                    cd.z = (short) file.ReadIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                }
                cd.width = (short) file.ReadUIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                cd.height = (short) file.ReadUIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                if (is3D) {
                    cd.length = (short) file.ReadUIntByByteCount(worldNeedLoader.CDAttributeByteCount);
                }
            }
        }
        // moduleEndOfHLLib\HLCDGroupAllTrans.LoadFromFile.Ccode
    }

    void RefreshTransInWorld(int gridWidth, int gridHeight) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RefreshTransInWorld.Ccode
        if (((HLList) items[TRANS_NONE]).items.length > 0) {
            HLList cdGroup = (HLList) items[TRANS_NONE];
            for (int i = 1; i < TRANS_COUNT; i++) {
                items[i] = GetTransCDGroup(cdGroup, i, gridWidth >> 1, gridHeight >> 1, false);
            }
        }
        // moduleEndOfHLLib\HLCDGroupAllTrans.RefreshTransInWorld.Ccode
    }

    void LoadFromSpriteFile(HLSpriteLoadInfo spriteNeedLoader, HLFile file) {
        int tempCount = file.ReadUIntByByteCount(spriteNeedLoader.SpriteCDCountByteCount);
        HLList cdGroup = new HLList(tempCount);
        if (tempCount > 0) {
            for (int i = 0; i < tempCount; i++) {
                HLCD cd = new HLCD();
                cdGroup.items[i] = cd;

                int[] values = new int[7];

                HLWorldObjectLoader.LoadValuesByLoader(values, spriteNeedLoader.spriteCDLoader, file);
                cd.mask = HLWorldObjectLoader.AdjustValue(values[0], spriteNeedLoader.SpriteCDMaskBitCount);
                cd.x = (short) HLWorldObjectLoader.AdjustValue(values[1], spriteNeedLoader.SpriteCDXBitCount);
                cd.y = (short) HLWorldObjectLoader.AdjustValue(values[2], spriteNeedLoader.SpriteCDYBitCount);
                cd.z = (short) HLWorldObjectLoader.AdjustValue(values[3], spriteNeedLoader.SpriteCDZBitCount);
                cd.width = (short) values[4];
                cd.height = (short) values[5];
                cd.length = (short) values[6];
            }
        }
        items[TRANS_NONE] = cdGroup;
    }

    void RefreshTransInSprite(int transEnable) {
        // moduleBeginOfHLLib\HLCDGroupAllTrans.RefreshTransInSprite.Ccode
        HLList cdGroup = (HLList) items[TRANS_NONE];
        for (int i = 1; i < TRANS_COUNT; i++) {
            if ((transEnable & (1 << i)) != 0 && ((HLCD) cdGroup.items[0]).mask != -1) {
                items[i] = GetTransCDGroup(cdGroup, i, 0, 0, true);
            } else {
                items[i] = cdGroup;
            }
        }
        // moduleEndOfHLLib\HLCDGroupAllTrans.RefreshTransInSprite.Ccode
    }
}
